#ifndef _BLOCKBREAKER_COMM_ISERIALIZABLE_H__
#define _BLOCKBREAKER_COMM_ISERIALIZABLE_H__

#include <iostream>

class ISerializable
{
    public:
        virtual unsigned int serialize(std::ostream& s) = 0;

    protected:
        /// Template to serialize any data type of fixed size
        template <class T> 
        static inline int write(std::ostream &s, T &v);

        /// Template to read any data type of fixed size
        template <class T> 
        static inline void read(std::istream &s, T &v);

        template <class T> 
        static inline int write(std::ostream &s, const T &v);

        /// For string serializing, first save the lenght using a short value (2 bytes)
        /// and then the string.
        template <>
        static inline int write(std::ostream &s, std::string &v);
        
        template <>
        static inline void read(std::istream &s, std::string &v);

        template <>
        static inline int write(std::ostream &s, const std::string &v);
};

template <class T>
static inline int ISerializable::write(std::ostream &s, T &v)
{
    s.write(reinterpret_cast<char *>(&v), sizeof(v));
    return sizeof(v);
}

template <class T>
static inline void ISerializable::read(std::istream &s, T &v)
{
    s.read(reinterpret_cast<char *>(&v), sizeof(v));
}

template <class T>
static inline int ISerializable::write(std::ostream &s, const T &v)
{
    s.write(reinterpret_cast<const char *>(&v), sizeof(v));
    return sizeof(v);
}

template <>
static inline int ISerializable::write(std::ostream &s, std::string &v)
{
    short len = (short) v.size();
    s.write(reinterpret_cast<char *>(&len), sizeof(short));
    s.write(v.c_str(), len + 1);
    return sizeof(short) + len + 1;
}

template <>
static inline void ISerializable::read(std::istream &s, std::string &v)
{
    short len;
    s.read(reinterpret_cast<char *>(&len), sizeof(short));
    char *buf = new char[len + 1];
    s.read(buf, len + 1);
    v = buf;
    delete[] buf;
}

template <>
static inline int ISerializable::write(std::ostream &s, const std::string &v)
{
    short len = (short) v.size();
    s.write(reinterpret_cast<char *>(&len), sizeof(short));
    s.write(v.c_str(), len + 1);
    return sizeof(short) + len + 1;
}
#endif // _BLOCKBREAKER_COMM_ISERIALIZABLE_H__
